package com.bjb.vr.common.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjb.vr.common.ao.OptCusDevDetailAo;
import com.bjb.vr.common.ao.ResDeviceAo;
import com.bjb.vr.common.constant.ThreadLocalConstant;
import com.bjb.vr.common.dto.*;
import com.bjb.vr.common.exception.CommonException;
import com.bjb.vr.common.mapper.ResContentMapper;
import com.bjb.vr.common.mapper.ResDevLoginRecordMapper;
import com.bjb.vr.common.mapper.ResDeviceMapper;
import com.bjb.vr.common.result.BaseErrorCode;
import com.bjb.vr.common.result.BaseResult;
import com.bjb.vr.common.result.CommonResult;
import com.bjb.vr.common.utils.ThreadLocalUtil;
import com.bjb.vr.common.vo.ClientLoginVo;
import com.bjb.vr.common.vo.OptCusDevDetailVo;
import com.bjb.vr.common.vo.ResDeviceInstContVo;
import com.bjb.vr.common.vo.ResDeviceVo;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;


/**
 * @author admin
 * @description 针对表【res_device(设备表)】的数据库操作Service实现
 * @createDate 2022-03-22 16:25:58
 */
@Service
public class ResDeviceService extends ServiceImpl<ResDeviceMapper, ResDevice> {

    @Autowired
    ResDeviceMapper resDeviceMapper;

    @Autowired
    ResContentMapper resContentMapper;

    @Resource
    private ResDevLoginRecordMapper devLoginRecordMapper;

    /**
     * 批量更新设备单机联网模式
     *
     * @param resDeviceList
     * @return
     */
    public BaseResult<ResDevice> updateResDeviceBatch(List<ResDevice> resDeviceList) {
        resDeviceMapper.updateResDeviceBatch(resDeviceList);
        return CommonResult.Ok();
    }

    /**
     * 更新设备表关联头盔大厅升级信息
     *
     * @param groupCode
     * @param sysUpdateId 系统升级关联表id
     * @param tenantId
     * @return
     */
    public BaseResult batchUpdateResDeviceSysUpdateId(String groupCode, Long sysUpdateId, String tenantId) {
        resDeviceMapper.batchUpdateResDeviceSysUpdateId(groupCode, sysUpdateId, tenantId);
        return CommonResult.Ok();
    }


    /**
     * 更新设备表单个设备关联头盔大厅升级信息
     *
     * @param groupCode
     * @param sysUpdateId
     * @param tenantId
     * @param udid
     * @return
     */
    public BaseResult updateResDeviceSysUpdateId(String groupCode, Long sysUpdateId, String tenantId, String udid) {
        resDeviceMapper.updateResDeviceSysUpdateId(groupCode, sysUpdateId, tenantId, udid);
        return CommonResult.Ok();
    }

    /**
     * 设备更新失败的设备更新状态为需要更新
     *
     * @param groupCode
     * @param apkNeedUpdateState
     * @return
     */
    public BaseResult batchUpdateFailResDeviceApkNeedUpdateState(String groupCode, int apkNeedUpdateState, String tenantId) {
        resDeviceMapper.batchUpdateFailResDeviceApkNeedUpdateState(groupCode, apkNeedUpdateState, tenantId);
        return CommonResult.Ok();
    }

    /**
     * 根据udid查询设备
     *
     * @param udid
     * @return
     */
    public BaseResult<ResDevice> getResDeviceByUdid(String udid) {
        BaseResult<ResDevice> result = new CommonResult<ResDevice>(false);
        LambdaQueryWrapper<ResDevice> queryWrapper = Wrappers.lambdaQuery(ResDevice.class);
        queryWrapper.eq(ResDevice::getUdid, udid);
        ResDevice resDevice = this.getOne(queryWrapper);
        if (resDevice != null) {
            result = CommonResult.Ok().setResult(resDevice);
        } else {
            result = CommonResult.Fail(BaseErrorCode.NOTFOUND.getCode(), "设备不存在");
        }
        return result;

    }


    /**
     * 根据udid获取设备登录返回信息
     *
     * @param udid
     * @return
     */
    public BaseResult<ClientLoginVo> getResDeviceLoginVoByUdid(String udid) {
        BaseResult<ClientLoginVo> result = new CommonResult<ResDevice>(false);
        MPJLambdaWrapper<ClientLoginVo> joinQueryWrapper = new MPJLambdaWrapper<>();
        joinQueryWrapper
                .selectAs(ResDevice::getId, "devId")
                .select(ResDevice::getUdid)
                .select(ResDevice::getMode)
                .select(ResDevice::getTenantId)
                .select(ResDevAuthorityDetail::getValidBegin)
                .select(ResDevAuthorityDetail::getValidEnd)
                .select(ResGroup::getThemeCode)
                .selectAs(SysConfig::getDevUpdState, "contUpdState")
                .select(ResDevice::getApkVerName)
                .selectAs(SysUpgrade::getVersion, "updateVersionName")
                .selectAs(ResDevice::getApkNeedUpdState, "dbApkNeedUpdState")
                .selectAs(SysUpgrade::getServerUrl, "downloadUrl")
                .leftJoin(SysUpgrade.class, on -> on.eq(SysUpgrade::getId, ResDevice::getSysUpdateId)
                        .eq(SysUpgrade::getPublishStatus, 1))
                .leftJoin(ResDevAuthorityDetail.class, ResDevAuthorityDetail::getUdid, ResDevice::getUdid)
                .leftJoin(ResGroup.class,ResGroup::getTenantId,ResDevice::getTenantId)
                .leftJoin(SysConfig.class, SysConfig::getTenantId, ResDevice::getTenantId);
        joinQueryWrapper.eq(ResDevice::getUdid, udid);
//        joinQueryWrapper.eq(SysUpgrade::getPublishStatus,1);
//        joinQueryWrapper.eq(ResDevice::getApkNeedUpdState, RemoteContants.APK_UPDATE_STATE_NEED);
        ClientLoginVo clientLoginVo = resDeviceMapper.selectJoinOne(ClientLoginVo.class, joinQueryWrapper);
        if (clientLoginVo != null) {
            result = CommonResult.Ok().setResult(clientLoginVo);
        } else {
            result = CommonResult.Fail(BaseErrorCode.NOTFOUND.getCode(), "设备不存在");
        }
        return result;

    }

    /**
     * 更新设备电量
     *
     * @param udid
     * @param battery
     * @return
     */
    public BaseResult updateResDeviceBatteryByUdid(String udid, float battery) {

        ResDevice resDevice = new ResDevice();
        resDevice.setBattery(Double.valueOf(battery));


        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备锁定状态
     *
     * @param udid
     * @param lockState
     * @return
     */
    public BaseResult updateResDeviceLockStateByUdid(String udid, int lockState) {

        ResDevice resDevice = new ResDevice();

        resDevice.setLockState(lockState);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备使用状态
     *
     * @param udid
     * @param useState
     * @return
     */
    public BaseResult updateResDeviceUseStateByUdid(String udid, int useState) {

        ResDevice resDevice = new ResDevice();

        resDevice.setUseState(useState);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备穿戴状态
     *
     * @param udid
     * @param wearState
     * @return
     */
    public BaseResult updateResDeviceWearStateByUdid(String udid, int wearState) {

        ResDevice resDevice = new ResDevice();

        resDevice.setWearState(wearState);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备播放状态
     *
     * @param udid
     * @param videoState
     * @return
     */
    public BaseResult updateResDeviceVideoStateByUdid(String udid, int videoState) {

        ResDevice resDevice = new ResDevice();

        resDevice.setVideoState(videoState);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备静音状态
     *
     * @param udid
     * @param soundState
     * @return
     */
    public BaseResult updateResDeviceSoundStateByUdid(String udid, int soundState) {

        ResDevice resDevice = new ResDevice();

        resDevice.setSoundState(soundState);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备控制模式
     *
     * @param udid
     * @param ctrlMode
     * @return
     */
    public BaseResult updateResDeviceCtrlModeByUdid(String udid, int ctrlMode) {

        ResDevice resDevice = new ResDevice();

        resDevice.setCtrlMode(ctrlMode);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }


    /**
     * 更新设备sd卡空间
     *
     * @param udid
     * @param space
     * @param sdSpace
     * @return
     */
    public BaseResult updateResDeviceSpaceByUdid(String udid, long space, long sdSpace) {

        ResDevice resDevice = new ResDevice();

        resDevice.setRemainMem(space);

        resDevice.setSdRemainMem(sdSpace);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新设备内存总空间
     *
     * @param udid
     * @param totalSpace
     * @param sdTotalSpace
     * @return
     */
    public BaseResult updateResDeviceTotalSpaceByUdid(String udid, long totalSpace, long sdTotalSpace) {

        ResDevice resDevice = new ResDevice();

        resDevice.setTotalMem(totalSpace);

        resDevice.setSdTotalMem(sdTotalSpace);

        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);

        wrapper.eq(ResDevice::getUdid, udid);

        boolean flag = this.update(resDevice, wrapper);

        if (flag)
            return CommonResult.Ok();

        return CommonResult.Fail();
    }

    /**
     * 更新课程加载状态
     *
     * @param udid
     * @param contentId
     * @param loadState
     * @param loadMsg
     * @return
     */
    public BaseResult updateResDeviceLoadStateByUdid(String udid, long contentId, int loadState, String loadMsg) {
        ResDevice resDevice = new ResDevice();
        resDevice.setContentLoadState(loadState);
        resDevice.setContentLoadMsg(loadMsg);
        resDevice.setCurContentId(contentId);
        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);
        wrapper.eq(ResDevice::getUdid, udid);
        boolean flag = this.update(resDevice, wrapper);
        if (flag)
            return CommonResult.Ok();
        return CommonResult.Fail();
    }


    /**
     * 更新设备在线离线状态
     *
     * @param udid
     * @param onlineState
     * @return
     */
    public BaseResult updateResDeviceOnlinieStateByUdid(String udid, int onlineState) {
        ResDevice resDevice = new ResDevice();
        resDevice.setOnlineState(onlineState);
        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);
        wrapper.eq(ResDevice::getUdid, udid);
        boolean flag = this.update(resDevice, wrapper);
        if (flag)
            return CommonResult.Ok();
        return CommonResult.Fail();
    }

    /**
     * 更新设备更新资源包状态
     *
     * @param udid
     * @param resBundleId
     * @param updateBundleState
     * @param updateBundleMsg
     * @return
     */
    public BaseResult updateResDeviceUpdateBundleStateByUdid(String udid, long resBundleId, int updateBundleState, String updateBundleMsg) {
        ResDevice resDevice = new ResDevice();
        resDevice.setCurBundleId(resBundleId);
        resDevice.setUpdateBundleState(updateBundleState);
        resDevice.setUpdateBundleMsg(updateBundleMsg);
        LambdaUpdateWrapper<ResDevice> wrapper = Wrappers.lambdaUpdate(ResDevice.class);
        wrapper.eq(ResDevice::getUdid, udid);
        boolean flag = this.update(resDevice, wrapper);
        if (flag)
            return CommonResult.Ok();
        return CommonResult.Fail();
    }

    /**
     * 上课时初始化所有设备的上课加载状态
     *
     * @param groupCode
     * @param contentId
     * @param loadState
     * @param loadMsg
     * @return
     */
    public void initDeviceClassLoadStateByGroupCode(String groupCode, long contentId, int loadState, String loadMsg) {
        resDeviceMapper.initDeviceClassLoadStateByGroupCode(groupCode, contentId, loadState, loadMsg);
    }

    /**
     * 初始化设备更新资源包状态
     *
     * @param groupCode
     * @param bundleId
     * @param updateBundleState
     * @param updateBundleMsg
     */
    public void initDeviceUpdateBundleStateByGroupCode(String groupCode, long bundleId, int updateBundleState, String updateBundleMsg) {
        resDeviceMapper.initDeviceUpdateBundleStateByGroupCode(groupCode, bundleId, updateBundleState, updateBundleMsg);
    }


    /**
     * 设备授权-获取选定租户设备分页记录
     *
     * @param resDeviceAo
     * @return
     */
    public IPage<ResDevice> queryResDevicePage(ResDeviceAo resDeviceAo) {
        Assert.notNull(resDeviceAo.getTenantId(), "租户id不能为空");

        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);

        // 分页条件
        Page<ResDevice> resDevicePage = new Page<>(resDeviceAo.getCurrent(), resDeviceAo.getSize());
        LambdaQueryWrapper<ResDevice> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(ResDevice::getTenantId, resDeviceAo.getTenantId());
//        lambdaQueryWrapper.eq(resDeviceAo.getOnlineState()!=null && resDeviceAo.getOnlineState()!=0,ResDevice::getOnlineState,resDeviceAo.getOnlineState());
        lambdaQueryWrapper.like(StringUtils.isNotBlank(resDeviceAo.getDevName()), ResDevice::getDevName, resDeviceAo.getDevName());

        Page<ResDevice> resDevicePage1 = this.page(resDevicePage, lambdaQueryWrapper);
        IPage<ResDevice> voIPage = new Page<ResDevice>(resDevicePage1.getCurrent(), resDevicePage1.getSize(), resDevicePage1.getTotal());
        voIPage.setRecords(resDevicePage1.getRecords());

        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, false);
        return voIPage;
    }

    /**
     * 设备管理-选定租户下的设备列表分页记录
     *
     * @param resDeviceAo
     * @return
     */
    public IPage<ResDeviceVo> queryCtrlResDevicePage(ResDeviceAo resDeviceAo) {

        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);

        // 分页条件
        Page<ResDeviceVo> resDevicePage = new Page<>(resDeviceAo.getCurrent(), resDeviceAo.getSize());

        MPJLambdaWrapper<ResDeviceVo> mpjLambdaWrapper = new MPJLambdaWrapper<>();
        mpjLambdaWrapper.selectAll(ResDevice.class)
                .select(ResGroup::getGroupName)
                .leftJoin(ResGroupRef.class, on -> on.eq(ResGroupRef::getDevUdid, ResDevice::getUdid)
                        .eq(ResGroupRef::getTenantId, ResDevice::getTenantId))
                .leftJoin(ResGroup.class, on -> on.eq(ResGroup::getId, ResGroupRef::getGroupId)
                        .eq(ResGroup::getTenantId, ResGroupRef::getTenantId));
        mpjLambdaWrapper.eq(StringUtils.isNotBlank(resDeviceAo.getTenantId()), ResDevice::getTenantId, resDeviceAo.getTenantId());
        mpjLambdaWrapper.eq(StringUtils.isNotBlank(resDeviceAo.getUdid()), ResDevice::getUdid, resDeviceAo.getUdid());
        mpjLambdaWrapper.eq(resDeviceAo.getOnlineState() != null && resDeviceAo.getOnlineState() != 0, ResDevice::getOnlineState, resDeviceAo.getOnlineState());


        IPage<ResDeviceVo> resDevicePage1 = resDeviceMapper.selectJoinPage(new Page<>(resDeviceAo.getCurrent(), resDeviceAo.getSize()), ResDeviceVo.class, mpjLambdaWrapper);

        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, false);
        return resDevicePage1;
    }

    /**
     * 获取设备详情
     * 运营管理-设备管理-设备详情
     *
     * @param resDeviceAo
     * @return
     */
    public BaseResult<ResDeviceVo> queryResDeviceDetail(ResDeviceAo resDeviceAo) {

        Assert.notNull(resDeviceAo.getUdid(), "设备udid不能为空!");
        Assert.notNull(resDeviceAo.getTenantId(), "租户id不能为空!");

        ResDeviceVo resDeviceVo = null;
        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);
        try {
            MPJLambdaWrapper<ResDeviceVo> mpjLambdaWrapper = new MPJLambdaWrapper<>();

            mpjLambdaWrapper.selectAll(ResDevice.class)
                    .select(ResGroup::getGroupName)
                    .leftJoin(ResGroupRef.class, on -> on.eq(ResGroupRef::getDevUdid, resDeviceAo.getUdid())
                            .eq(ResGroupRef::getTenantId, resDeviceAo.getTenantId()))
                    .leftJoin(ResGroup.class, on -> on.eq(ResGroup::getId, ResGroupRef::getGroupId)
                            .eq(ResGroupRef::getTenantId, resDeviceAo.getTenantId()));
            mpjLambdaWrapper.eq(ResDevice::getUdid, resDeviceAo.getUdid());

            resDeviceVo = resDeviceMapper.selectJoinOne(ResDeviceVo.class, mpjLambdaWrapper);
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error(ex.getMessage());
            throw new CommonException("获取设备详情失败");
        } finally {
            ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, false);
        }
        return CommonResult.Ok().setResult(resDeviceVo);
    }

    /**
     * 设备管理-查询单台设备安装课程分页列表
     *
     * @param resDeviceAo
     * @return
     */
    public IPage<ResDeviceInstContVo> queryResDeviceInstContentPage(ResDeviceAo resDeviceAo) {

        Assert.notNull(resDeviceAo.getUdid(), "设备udid不能为空!");
        Assert.notNull(resDeviceAo.getTenantId(), "租户id不能为空!");

        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);
        // 分页条件
        MPJLambdaWrapper<ResDeviceInstContVo> mpjLambdaWrapper = new MPJLambdaWrapper();
        mpjLambdaWrapper.select(ResContent::getName)
                .innerJoin(ResDeviceContent.class, on -> on.eq(ResDeviceContent::getContentId, ResContent::getId)
                        .like(StringUtils.isNotBlank(resDeviceAo.getInstCntName()), ResContent::getName, resDeviceAo.getInstCntName()));
        mpjLambdaWrapper.eq(ResDeviceContent::getUdid, resDeviceAo.getUdid());
        mpjLambdaWrapper.eq(ResDeviceContent::getTenantId, resDeviceAo.getTenantId());
        IPage<ResDeviceInstContVo> iPage = resContentMapper.selectJoinPage(new Page<>(resDeviceAo.getCurrent(), resDeviceAo.getSize()), ResDeviceInstContVo.class, mpjLambdaWrapper);
        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, false);
        return iPage;
    }

    /**
     * 运营端统计页面-设备详情分页查询
     *
     * @param optCusDevDetailAo
     * @return
     */
    public IPage<OptCusDevDetailVo> getDevicesByPage(OptCusDevDetailAo optCusDevDetailAo) {
        ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);
        MPJLambdaWrapper<OptCusDevDetailVo> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper.select(ResDevice::getId)
                .select(SysTenant::getTenantName)
                .selectAs(ResDevice::getDevName, "deviceName")
                .selectAs(ResDevice::getUdid, "deviceId")
                .selectAs(ResDevLoginRecord::getDevUseTime, "userTime")
                .selectAs(ResDevLoginRecord::getDevLoginTime, "loginTime")
                .selectAs(ResDevLoginRecord::getDevLogoutTime, "logoutTime")
                .innerJoin(ResDevLoginRecord.class, ResDevLoginRecord::getUdid, ResDevice::getUdid)
                .innerJoin(SysTenant.class, SysTenant::getTenantId, ResDevice::getTenantId);
        // 查询条件
        queryWrapper.eq(StringUtils.isNotBlank(optCusDevDetailAo.getTenantId()), ResDevice::getTenantId, optCusDevDetailAo.getTenantId());
        queryWrapper.gt(Objects.nonNull(optCusDevDetailAo.getLoginTime()), ResDevLoginRecord::getDevLoginTime, optCusDevDetailAo.getLoginTime());
        queryWrapper.lt(Objects.nonNull(optCusDevDetailAo.getLogoutTime()), ResDevLoginRecord::getDevLogoutTime, optCusDevDetailAo.getLogoutTime());
        IPage<OptCusDevDetailVo> loginRecordPage = resDeviceMapper.selectJoinPage(new Page<>(optCusDevDetailAo.getCurrent(), optCusDevDetailAo.getSize()), OptCusDevDetailVo.class, queryWrapper);
        loginRecordPage.getRecords().stream().forEach(p ->{
            if (Objects.isNull(p.getUserTime())){
                p.setUserTime(0f);
            }
        });
        return loginRecordPage;
    }
}




